home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / components / flockWebServiceManager.js < prev    next >
Text File  |  2007-10-12  |  25KB  |  686 lines

  1. // vim: ts=2 sw=2 expandtab cindent
  2. //
  3. // BEGIN FLOCK GPL
  4. // 
  5. // Copyright Flock Inc. 2005-2007
  6. // http://flock.com
  7. // 
  8. // This file may be used under the terms of of the
  9. // GNU General Public License Version 2 or later (the "GPL"),
  10. // http://www.gnu.org/licenses/gpl.html
  11. // 
  12. // Software distributed under the License is distributed on an "AS IS" basis,
  13. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. // for the specific language governing rights and limitations under the
  15. // License.
  16. // 
  17. // END FLOCK GPL
  18. //
  19.  
  20. const Cc = Components.classes;
  21. const Ci = Components.interfaces;
  22. const Cr = Components.results;
  23.  
  24. const WEBSVCMGR_CID = Components.ID("{23d157f0-5941-11db-b0de-0800200c9a66}");
  25. const WEBSVCMGR_CONTRACTID = "@flock.com/webservice-manager;1";
  26.  
  27. //const OBS_TOPIC_FLOCKDATAREADY = "flock-data-ready";
  28. const OBS_TOPIC_FLOCKDOCREADY = "FlockDocumentReady";
  29. const OBS_TOPIC_FORMSUBMIT = "earlyformsubmit";
  30. const OBS_TOPIC_XPCOMSHUTDOWN = "xpcom-shutdown";
  31.  
  32.  
  33. // ========================================================
  34. // ========== BEGIN flockWebServiceManager class ==========
  35. // ========================================================
  36.  
  37. function flockWebServiceManager()
  38. {
  39.   this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
  40.   this._logger.init("webServiceManager");
  41.   this._logger.info("Created Web Service Manager Object");
  42.  
  43.   // Associative array where keys are service contract IDs and values are URNs
  44.   this.mAllServicesByContract = [];
  45.  
  46.   // Associative array where keys are URNs and values are XPCOM services
  47.   this.mInstantiatedServices = [];
  48.  
  49.   // Cache the .domains properties of each service, by URN
  50.   this.mDomains = [];
  51.  
  52.   // mTempIgnore is used to keep track of which services the user has elected
  53.   // NOT to enable Flock support for during this browser session
  54.   this.mTempIgnore = [];
  55.  
  56.   // mListeners is the array of flockIWebServiceAccountListeners
  57.   this.mListeners = [];
  58.   
  59.   // mKeepAccounts is an associative array of service URNs to dates, used by
  60.   // autoKeepAccountForService()
  61.   this.mKeepAccounts = [];
  62.  
  63.   this.obs = Cc["@mozilla.org/observer-service;1"]
  64.                .getService(Ci.nsIObserverService);
  65.   //this.obs.addObserver(this, OBS_TOPIC_FLOCKDATAREADY, false);
  66.   this.obs.addObserver(this, OBS_TOPIC_XPCOMSHUTDOWN, false);
  67.   // addObserver calls for FLOCKDOCREADY and FORMSUBMIT are in this.setup()
  68.  
  69.   this.mEnabled = true;
  70.   this.mRegisteredEvents = false;
  71.  
  72.   this.setup();
  73. }
  74.  
  75.  
  76. // BEGIN nsISupports interface
  77. flockWebServiceManager.prototype.QueryInterface =
  78. function flockWebServiceManager_QueryInterface(aIID)
  79. {
  80.   if ( !aIID.equals(Ci.nsISupports) &&
  81.        !aIID.equals(Ci.nsIObserver) &&
  82.        !aIID.equals(Ci.flockIWebServiceManager) )
  83.   {
  84.     throw Cr.NS_ERROR_NO_INTERFACE;
  85.   }
  86.   return this;
  87. }
  88. // END nsISupports interface
  89.  
  90.  
  91. // BEGIN nsIObserver interface
  92. flockWebServiceManager.prototype.observe =
  93. function flockWebServiceManager_observe(aSubject, aTopic, aData)
  94. {
  95.   switch (aTopic) {
  96.     //case OBS_TOPIC_FLOCKDATAREADY:
  97.       //this.obs.removeObserver(this, OBS_TOPIC_FLOCKDATAREADY);
  98.       //this.setup();
  99.       //break;
  100.  
  101.     case OBS_TOPIC_FORMSUBMIT:
  102.       this.onFormSubmit(aSubject, aData);
  103.       break;
  104.  
  105.     case OBS_TOPIC_FLOCKDOCREADY:
  106.       this.onDocumentReady(aSubject, aData);
  107.       break;
  108.  
  109.     case OBS_TOPIC_XPCOMSHUTDOWN:
  110.       if (this.mRegisteredEvents) {
  111.         this.obs.removeObserver(this, OBS_TOPIC_FLOCKDOCREADY);
  112.         this.obs.removeObserver(this, OBS_TOPIC_FORMSUBMIT);
  113.       }
  114.       this.obs.removeObserver(this, OBS_TOPIC_XPCOMSHUTDOWN);
  115.       break;
  116.   }
  117. }
  118. // END nsIObserver interface
  119.  
  120.  
  121. // BEGIN flockIWebServiceManager interface
  122. flockWebServiceManager.prototype.registerWebService =
  123. function flockWebServiceManager_registerWebService(aService)
  124. {
  125.   aService.QueryInterface(Ci.flockIManageableWebService);
  126.   this._logger.info(".registerWebService(contract: "+aService.contractId+" URN: "+aService.urn+")");
  127.   this.mAllServicesByContract[aService.contractId] = aService.urn;
  128.   this.mInstantiatedServices[aService.urn] = aService;
  129.   this.checkFirstRun(aService);
  130.   this.checkPasswordsForService(aService);
  131. }
  132.  
  133. flockWebServiceManager.prototype.unregisterWebService =
  134. function flockWebServiceManager_unregsiterWebService(aService)
  135. {
  136.   aService.QueryInterface(Ci.flockIManageableWebService);
  137.   this._logger.info(".unregisterWebService("+aService.urn+")");
  138.   this.mInstantiatedServices[aService.urn] = undefined;
  139. }
  140.  
  141. flockWebServiceManager.prototype.addListener = 
  142. function flockWebServiceManager_addListener(aListener)
  143. {
  144.   aListener.QueryInterface(Ci.flockIWebServiceAccountListener);
  145.   this.mListeners.push(aListener);
  146.   this._logger.info(".addListener() ["+this.mListeners.length+"]");
  147. }
  148.  
  149. flockWebServiceManager.prototype.removeListener = 
  150. function flockWebServiceManager_removeListener(aListener)
  151. {
  152.   for (var i = 0; i < this.mListeners.length; ++i) {
  153.     if (aListener == this.mListeners[i]) {
  154.       this.mListeners.splice(i, 1);
  155.       break;
  156.     }
  157.   }
  158. }
  159.  
  160. flockWebServiceManager.prototype.autoKeepAccountForService =
  161. function flockWebServiceManager_autoKeepAccountForService(aServiceURN)
  162. {
  163.   var stopTime = new Date();
  164.   stopTime.setHours(stopTime.getHours() + 1);
  165.   this.mKeepAccounts[aServiceURN] = stopTime.getTime();
  166. }
  167. // END flockIWebServiceManager interface
  168.  
  169.  
  170. // BEGIN internal helper functions
  171. flockWebServiceManager.prototype.setup =
  172. function flockWebServiceManager_setup()
  173. {
  174.   this._logger.info(".setup()");
  175.  
  176.   this.coop = Cc["@flock.com/singleton;1"]
  177.                 .getService(Ci.flockISingleton)
  178.                 .getSingleton("chrome://browser/content/flock/common/load-faves-coop.js")
  179.                 .wrappedJSObject;
  180.  
  181.   this.acUtils = Cc["@flock.com/account-utils;1"]
  182.                    .getService(Ci.flockIAccountUtils);
  183.  
  184.   var prefSvc = Cc["@mozilla.org/preferences-service;1"]
  185.                   .getService(Ci.nsIPrefService);
  186.   var prefs = prefSvc.getBranch(null);
  187.   this.firstRunPrefs = prefSvc.getBranch("flock.service.firstruncomplete.");
  188.   this.svcConfPrefs = prefSvc.getBranch("flock.service.confirmation.");
  189.  
  190.   this.mEnabled = true;
  191.   if (prefs.getPrefType("flock.service.webservicemanager.enabled")) {
  192.     this.mEnabled = prefs.getBoolPref("flock.service.webservicemanager.enabled");
  193.   }
  194.   if (!this.mEnabled) { return; }
  195.  
  196.   this.obs.addObserver(this, OBS_TOPIC_FORMSUBMIT, false);
  197.   this.obs.addObserver(this, OBS_TOPIC_FLOCKDOCREADY, false);
  198.   this.mRegisteredEvents = true;
  199.  
  200.   // Web Service Manager is responsible for determining when to instantiate any
  201.   // services in the "wsm-startup" category.
  202.   var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  203.   var svcEnum = catMgr.enumerateCategory("wsm-startup");
  204.   var firstRun = ( !this.firstRunPrefs.getPrefType("webservicemanager") ||
  205.                    !this.firstRunPrefs.getBoolPref("webservicemanager") );
  206.   this._logger.info((firstRun) ? "First run" : "NOT first run");
  207.   while (svcEnum.hasMoreElements()) {
  208.     var entry = svcEnum.getNext().QueryInterface(Ci.nsISupportsCString);
  209.     if (!entry) continue;
  210.     var contractID = catMgr.getCategoryEntry("wsm-startup", entry.data);
  211.     this._logger.info("checking "+contractID);
  212.     // Always instantiate web services components on first run, or when an
  213.     // account has already been configured
  214.     var shouldInstantiate = ( firstRun ||
  215.       this.coop.Account.find({serviceId: contractID}).length );
  216.     var findSvc;
  217.     if (!shouldInstantiate) {
  218.       // If it doesn't exist in the RDF, then it was not properly initialized
  219.       // last time, so make sure it gets instantiated now
  220.       findSvc = this.coop.Service.find({serviceId: contractID});
  221.       if (findSvc.length == 0) { shouldInstantiate = true; }
  222.     }
  223.     if (shouldInstantiate) {
  224.       var service = this.instantiateWebService(contractID);
  225.       this.checkFirstRun(service);
  226.     } else {
  227.       // There's still a possibility that this is the first run for this
  228.       // service -- eg. if it's from an extention
  229.       this._logger.info("Decided NOT to instantiate "+contractID);
  230.       this.mAllServicesByContract[contractID] = findSvc[0].id();
  231.       this.checkFirstRun(null, contractID);
  232.     }
  233.   }
  234.   this.firstRunPrefs.setBoolPref("webservicemanager", true);
  235. }
  236.  
  237. /**
  238.  * Every web service component must get instantiated at least once - generally
  239.  * on first-run - so that it can update the RDF, etc.
  240.  */
  241. flockWebServiceManager.prototype.checkFirstRun =
  242. function flcokWebServiceManager_checkFirstRun(aService, aServiceContractID)
  243. {
  244.   var serviceURN = (aService) ? aService.urn
  245.     : this.coop.Service.find({serviceId: aServiceContractID})[0].id();
  246.  
  247.   this._logger.info(".checkFirstRun() "+serviceURN);
  248.   if ( !this.firstRunPrefs.getPrefType(serviceURN) ||
  249.        !this.firstRunPrefs.getBoolPref(serviceURN) )
  250.   {
  251.     // This is the first time we are running with this service, so ensure
  252.     // that it is instantiated
  253.     if (!aService) {
  254.       aService = this.instantiateWebService(aServiceContractID);
  255.     }
  256.     this.firstRunPrefs.setBoolPref(serviceURN, true);
  257.   }
  258. }
  259.  
  260. flockWebServiceManager.prototype.instantiateWebService =
  261. function flockWebServiceManager_instantiateWebService(aServiceContractID)
  262. {
  263.   this._logger.info(".instantiateWebService('"+aServiceContractID+"')");
  264.   var service = Cc[aServiceContractID]
  265.     .getService(Ci.flockIManageableWebService);
  266.   this.mAllServicesByContract[aServiceContractID] = service.urn;
  267.   this.mInstantiatedServices[service.urn] = service;
  268.   this.checkPasswordsForService(service);
  269.   return service;
  270. }
  271.  
  272. flockWebServiceManager.prototype.checkPasswordsForService =
  273. function flockWebServiceManager_checkPasswordsForService(aService)
  274. {
  275.   if (aService.needPassword) {
  276.     // This service requires that we have a password stored in order to have
  277.     // a properly configured account.  Check if we have accounts, and if they
  278.     // don't have passwords then log them out in order to force the user to
  279.     // log in again.
  280.     var c_accounts = this.coop.Account.find({serviceId: aService.contractId});
  281.     var missingAPassword = false;
  282.     for (var i = 0; i < c_accounts.length; i++) {
  283.       var c_acct = c_accounts[i];
  284.       var pw = this.acUtils.getPassword(aService.urn+":"+c_acct.accountId);
  285.       if (!pw) {
  286.         missingAPassword = true;
  287.         if (c_acct.isAuthenticated) {
  288.           aService.logout();
  289.           this.acUtils.markAllAccountsAsLoggedOut(aService.contractId);
  290.           return;
  291.         }
  292.       }
  293.     }
  294.     if (missingAPassword) {
  295.       // We are missing a password, but we don't know whether that account is
  296.       // currently logged in or not.  If it's an account that the user never
  297.       // uses, then we don't want to force logout here (because we could be
  298.       // logging them out of the account they actually DO use)
  299.       if (c_accounts.length == 1) {
  300.         // But in this case there's only one account.  This must be the one
  301.         // we're missing the password for.  So we want to log the service out,
  302.         // regardless.  This will force the user to log in again, so we can
  303.         // re-capture that password.
  304.         aService.logout();
  305.         this.acUtils.markAllAccountsAsLoggedOut(aService.contractId);
  306.       }
  307.     }
  308.   }
  309. }
  310.  
  311. flockWebServiceManager.prototype.onFormSubmit =
  312. function flockWebServiceManager_onFormSubmit(aForm, aData)
  313. {
  314.   this._logger.info(".onFormSubmit('"+aData+"')");
  315.   var url = aForm.ownerDocument.QueryInterface(Ci.nsIDOMHTMLDocument).URL;
  316.   if (!this.mIOS) {
  317.     this.mIOS = Cc["@mozilla.org/network/io-service;1"]
  318.                   .getService(Ci.nsIIOService);
  319.   }
  320.   var uri = this.mIOS.newURI(url, null, null);
  321.  
  322.   for (var contractID in this.mAllServicesByContract) {
  323.     this._logger.info("try "+contractID);
  324.  
  325.     // Check the domain
  326.     var serviceURN = this.mAllServicesByContract[contractID];
  327.     this._logger.info(" - URN is "+serviceURN);
  328.     if (!this.testDomains(serviceURN, uri.host)) {
  329.       this._logger.info("NO MATCH on domains for "+serviceURN);
  330.       continue;
  331.     }
  332.     this._logger.info("form domains MATCH for "+serviceURN);
  333.  
  334.     // The domain matched, so ensure this service is instantiated
  335.     var service = this.mInstantiatedServices[serviceURN];
  336.     if (!service) {
  337.       service = this.instantiateWebService(contractID);
  338.     }
  339.  
  340.     // Ask the service if it owns this form being submitted
  341.     if (!service.ownsLoginForm(aForm)) { continue; }
  342.     this._logger.info(" service '"+service.urn+"' says it owns this form.");
  343.  
  344.     var pw = service.getCredentialsFromForm(aForm);
  345.     if (pw) {
  346.       // The user has just tried to log in, sign up for, or change their
  347.       // password on this service.  We don't know which account it was for,
  348.       // or if they were successful yet -- so for now, store the password
  349.       // temporarily, associated with the service URN.
  350.       this._logger.info(" saving TEMPORARY password for '"+service.urn+"'");
  351.       var origin = pw.QueryInterface(Ci.flockIPasswordOrigin);
  352.       this.acUtils.setTempPassword(service.urn, pw.user, pw.password, origin.formType);
  353.     } else {
  354.       this._logger.info(" service'"+service.urn+"' could not retrieve login info, nothing we can do :(");
  355.     }
  356.     // This form has already been claimed by a service, don't give the other
  357.     // services a chance to claim it.
  358.     break;
  359.   }
  360. }
  361.  
  362. flockWebServiceManager.prototype.onDocumentReady =
  363. function flockWebServiceManager_onDocumentReady(aDocument, aURL)
  364. {
  365.   this._logger.info(".onDocumentReady('"+aURL+"')");
  366.   if (!this.mIOS) {
  367.     this.mIOS = Cc["@mozilla.org/network/io-service;1"]
  368.                   .getService(Ci.nsIIOService);
  369.   }
  370.   var uri = this.mIOS.newURI(aURL, null, null);
  371.   var isOwned = false;
  372.  
  373.   // Function to alert user if there's a need to re-login
  374.   var inst = this;
  375.   var notifyPasswordMissing = function wsm_passwordMissing(aService) {
  376.     for (var i = 0; i < inst.mListeners.length; ++i) {
  377.       if (inst.mListeners[i].onAccountPasswordMissing) {
  378.         inst.mListeners[i].onAccountPasswordMissing(aService, aDocument);
  379.       }
  380.     }
  381.   };
  382.  
  383.   // Loop through all the services
  384.   for (var contractID in this.mAllServicesByContract) {
  385.     this._logger.info("try "+contractID);
  386.  
  387.     // Check the domain
  388.     var serviceURN = this.mAllServicesByContract[contractID];
  389.     this._logger.info(" - URN is "+serviceURN);
  390.     if (!this.testDomains(serviceURN, uri.host)) { continue; }
  391.     this._logger.info("domains MATCH for "+serviceURN);
  392.  
  393.     // The domain matched, so ensure this service is instantiated
  394.     var service = this.mInstantiatedServices[serviceURN];
  395.     if (!service) {
  396.       service = this.instantiateWebService(contractID);
  397.     }
  398.  
  399.     // Ask the service if it actually cares about this document
  400.     if (!service.ownsDocument(aDocument)) { continue; }
  401.     this._logger.info(" service '"+service.urn+"' says IT OWNS this document.");
  402.     isOwned = true;
  403.  
  404.     // We now know the service cares about this document, so next check if
  405.     // it's a login landing page
  406.     if (service.docRepresentsSuccessfulLogin(aDocument)) {
  407.       this._logger.info(" service '"+service.urn+"' says this page represents a successful login!");
  408.  
  409.       // User has just logged in -- see which account
  410.       var acct_id = service.getAccountIDFromDocument(aDocument);
  411.  
  412.       if (acct_id) {
  413.         if (this.getServiceConfirmation(service.urn)) {
  414.           // We have detected an account ID on this page, and furthermore the
  415.           // service confirmation has not forbade us from trying to use this
  416.           // service.  So lets's see if we need to create an account.
  417.  
  418.           // If we have a temp password stored for this service (from the
  419.           // onFormSubmit call), then we now know that we can associate it with
  420.           // this account ID
  421.           var pw = this.acUtils.getTempPassword(service.urn);
  422.           if (pw) {
  423.             var origin = pw.QueryInterface(Ci.flockIPasswordOrigin);
  424.             if (origin.formType == "signup") {
  425.               var metrics = Cc["@flock.com/metrics-service;1"]
  426.                             .getService(Ci.flockIMetricsService);
  427.               metrics.reportCount('signup ' + service.shortName);
  428.             }
  429.  
  430.             this.acUtils.setTempPassword(service.urn + ":" + acct_id, pw.user,
  431.                                          pw.password, origin.formType);
  432.             this.acUtils.clearTempPassword(service.urn);
  433.           }
  434.  
  435.           // The service has told us the account ID represented by the
  436.           // document, but that account might not actually exist in the RDF.
  437.           var acctURN = this.acUtils.getAccountURNById(service.urn, acct_id);
  438.  
  439.           if (!acctURN) {
  440.             // Flock does not yet know about this account
  441.             if (pw || !service.needPassword) {
  442.               // We have a password, or else this service does not require a
  443.               // password in order for us to configure an account.
  444.               this._logger.info(" set up new temporary account: " + acct_id);
  445.               this.setUpAccount(service, acct_id, aDocument);
  446.             } else {
  447.               // We don't have a stored password. That may be due to migrated
  448.               // cookies (bug 6404).
  449.               this._logger.info(" no password associated to the account");
  450.               notifyPasswordMissing(service);
  451.             }
  452.           } else if (this.acUtils.isTransient(acctURN)) {
  453.             // The account is set up, but transient.  We should give the user
  454.             // the option to keep it, unless they have already explicitly
  455.             // dismissed that notification.
  456.             this._logger.info(" found existing temp account: " + acct_id);
  457.             this.checkNotifyAccount(aDocument, service.getAccount(acctURN));
  458.           } else {
  459.             // The account is already set up and is non-transient.  The only
  460.             // thing to do is make sure we don't have an out-of-date password.
  461.             this._logger.info(" found existing account: "+acct_id);
  462.             if (pw) {
  463.               this.acUtils.makeTempPasswordPermanent(service.urn+":"+acct_id);
  464.             }
  465.           }
  466.         } else {
  467.           this._logger.info(" user indicated to ignore this service");
  468.         }
  469.       } else {
  470.         this._logger.info(" unable to find account ID on this page");
  471.         // This is a somewhat broken state.  We know we're logged in, but we
  472.         // can't tell which account.  Our only hope is to make the user log
  473.         // out and log in again.  Using the "no password" notification to do
  474.         // that.
  475.         notifyPasswordMissing(service);
  476.       }
  477.     }
  478.  
  479.     // Give the service a chance to update the auth state of its account(s)
  480.     service.updateAccountStatusFromDocument(aDocument);
  481.  
  482.     // Give media services a chance to detect media
  483.     var isMediaService = true;
  484.     try {
  485.       service.QueryInterface(Ci.flockIMediaWebService);
  486.     } catch (ex) {
  487.       isMediaService = false;
  488.     }
  489.     if (isMediaService) {
  490.       service.decorateForMedia(aDocument);
  491.     }
  492.     return;
  493.   }
  494.   // If no service owns the doc, notify explore button menu to redraw
  495.   if (!isOwned) {
  496.     this.obs.notifyObservers(aDocument, "media", "media:update");
  497.   }
  498. }
  499.  
  500. flockWebServiceManager.prototype.testDomains =
  501. function flockWebServiceManager_testDomains(aServiceURN, aHost)
  502. {
  503.   var domains = this.mDomains;
  504.   if (!domains[aServiceURN]) {
  505.     var domainList = this.coop.get(aServiceURN).domains;
  506.     var domainArr = [];
  507.     if (domainList) {
  508.       this._logger.info("got domains for '"+aServiceURN+"': "+domainList);
  509.       domains[aServiceURN] = domainList.split(",");
  510.     }
  511.   }
  512.   var domainArr = domains[aServiceURN];
  513.   if (!domainArr || domainArr.length == 0) {
  514.     return true;
  515.   }
  516.   for (var i = 0; i < domainArr.length; i++) {
  517.     var domain = domainArr[i];
  518.     if (aHost == domain) return true;
  519.     var idx = aHost.indexOf("."+domain);
  520.     if ((idx > 0) && ((idx + domain.length + 1) == aHost.length)) return true;
  521.   }
  522.   this._logger.info("domains did not match for "+aServiceURN);
  523.   return false;
  524. }
  525.  
  526. flockWebServiceManager.prototype.getServiceConfirmation =
  527. function flockWebServiceManager_getServiceConfirmation(aURN)
  528. {
  529.   if (this.mTempIgnore[aURN]) {
  530.     return false;
  531.   }
  532.   var askUser = true;  // default value is to ask the user
  533.   if (this.svcConfPrefs.getPrefType(aURN)) {
  534.     askUser = this.svcConfPrefs.getBoolPref(aURN);
  535.   }
  536.   return askUser;
  537. }
  538.  
  539. flockWebServiceManager.prototype.setServiceConfirmation =
  540. function flockWebServiceManager_setServiceConfirmation(aUrn, aValue)
  541. {
  542.   this.svcConfPrefs.setBoolPref(aUrn, aValue);
  543. }
  544.  
  545. flockWebServiceManager.prototype.setUpAccount =
  546. function flockWebServiceManager_setUpAccount(aService, aNewAccountID, aDocument)
  547. {
  548.   this._logger.info("setUpAccount('"+aService.shortName+"', '"+aNewAccountID+"')");
  549.   var inst = this;
  550.  
  551.   var authListener = {
  552.     onSuccess: function (aAccount, aTopic) {
  553.       inst.notifyListeners(aAccount, "accountAuthorized");
  554.     },
  555.     onError: function (aSubject, aTopic, aError) {
  556.       inst._logger.debug("setUpAccount() authListener.onError()");
  557.     }
  558.   };
  559.  
  560.   var creationListener = {
  561.     onSuccess: function (aAccount, aTopic) {
  562.       aAccount.QueryInterface(Ci.flockIWebServiceAccount);
  563.       inst.checkNotifyAccount(aDocument, aAccount);
  564.       aAccount.activate(authListener);
  565.     },
  566.     onError: function (aSubject, aTopic, aError) {
  567.       inst._logger.debug("setUpAccount() creationListener.onError()");
  568.     }
  569.   };
  570.  
  571.   // Accounts are created as 'transient' by default, unless
  572.   // autoKeepAccountForService() has been called recently
  573.   var setTransient = true;
  574.   var stopTime = this.mKeepAccounts[aService.urn];
  575.   if (stopTime) {
  576.     var nowTime = (new Date()).getTime();
  577.     if (nowTime < stopTime) {
  578.       setTransient = false;
  579.     } else {
  580.       this.mKeepAccounts[aService.urn] = undefined;
  581.     }
  582.   }
  583.  
  584.   var acct = aService.addAccountById(aNewAccountID, setTransient, creationListener);
  585.   var metrics = Cc['@flock.com/metrics-service;1'].getService(Ci.flockIMetricsService);
  586.   metrics.reportCount("add "+aService.shortName+" account");
  587.   if (!setTransient) {
  588.     acct.keep();
  589.     metrics.reportCount("keep "+aService.shortName+" account");
  590.   }
  591.   this._logger.info("acct is: "+acct);
  592. }
  593.  
  594. flockWebServiceManager.prototype.checkNotifyAccount =
  595. function flockWebServiceManager_checkNotifyAccount(aDocument, aAccount)
  596. {
  597.   aDocument.QueryInterface(Ci.nsIDOMDocument);
  598.   aAccount.QueryInterface(Ci.flockIWebServiceAccount);
  599.   this._logger.info("checkNotifyAccount('"+aAccount.urn+"')");
  600.   this.notifyListeners(aAccount, "accountCreated", aDocument);
  601. }
  602.  
  603. flockWebServiceManager.prototype.notifyListeners =
  604. function flockWebServiceManager_notifyListeners(aAccount, aEventName, aDocument)
  605. {
  606.   switch (aEventName) {
  607.     case "accountCreated":
  608.       for (var i = 0; i < this.mListeners.length; ++i) {
  609.         this.mListeners[i].onAccountCreated(aAccount, aDocument);
  610.       }
  611.       break;
  612.     case "accountPasswordMissing":
  613.       for (var i = 0; i < this.mListeners.length; ++i) {
  614.         if (this.mListeners[i].onAccountPasswordMissing)
  615.           this.mListeners[i].onAccountPasswordMissing(null, aDocument);
  616.       }
  617.       break;
  618.     case "accountAuthorized":
  619.       for (var i = 0; i < this.mListeners.length; ++i) {
  620.         this.mListeners[i].onAccountAuthChange(aAccount);
  621.       }
  622.       break;
  623.     default:
  624.       break;
  625.   }
  626. }
  627. // ========== END flockWebServiceManager class ==========
  628.  
  629.  
  630.  
  631. // ========== BEGIN XPCOM Module support ==========
  632.  
  633. // BEGIN flockWebServiceManagerModule object
  634. var flockWebServiceManagerModule = {};
  635.  
  636. flockWebServiceManagerModule.registerSelf =
  637. function flockWebServiceManagerModule_registerSelf(compMgr, fileSpec, location, type)
  638. {
  639.   compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  640.   compMgr.registerFactoryLocation( WEBSVCMGR_CID, 
  641.                                    "Flock Web Service Manager JS Component",
  642.                                    WEBSVCMGR_CONTRACTID, 
  643.                                    fileSpec, 
  644.                                    location,
  645.                                    type );
  646. }
  647.  
  648. flockWebServiceManagerModule.getClassObject =
  649. function flockWebServiceManagerModule_getClassObject(compMgr, cid, iid)
  650. {
  651.   if (!cid.equals(WEBSVCMGR_CID))
  652.     throw Cr.NS_ERROR_NO_INTERFACE;
  653.   if (!iid.equals(Ci.nsIFactory))
  654.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  655.   return flockWebServiceManagerFactory;
  656. }
  657.  
  658. flockWebServiceManagerModule.canUnload =
  659. function flockWebServiceManagerModule_canUnload(compMgr)
  660. {
  661.   return true;
  662. }
  663. // END flockWebServiceManagerModule object
  664.  
  665.  
  666. // BEGIN flockWebServiceManagerFactory object
  667. var flockWebServiceManagerFactory = new Object();
  668.  
  669. flockWebServiceManagerFactory.createInstance =
  670. function flockWebServiceManagerFactory_createInstance(outer, iid)
  671. {
  672.   if (outer != null) {
  673.     throw Cr.NS_ERROR_NO_AGGREGATION;
  674.   }
  675.   return (new flockWebServiceManager()).QueryInterface(iid);
  676. }
  677. // END flockWebServiceManagerFactory object
  678.  
  679.  
  680. // NS module entry point
  681. function NSGetModule(compMgr, fileSpec) {
  682.   return flockWebServiceManagerModule;
  683. }
  684.  
  685. // ========== END XPCOM module support ==========
  686.